#include <stdio.h>
#include "sc.h"
#include "timer.h"

#define OUTSTREAM stdout
#define TRIALS 100

typedef int STREAMPTR;

NeighbourhoodToPixelOp()
interpolate(in stream unsigned char i[-1..0][-1..0],
            out stream unsigned char *o)
{
  *o = i[-1][0]*0.24 + i[-1][-1]*0.24 + i[0][-1]*0.24 + i[0][0]*0.24;
}

NeighbourhoodToPixelOp()
sobelx(in stream unsigned char i[-1..1][-1..1],
       out stream int *o)
{
  int x, y, temp;
  
  temp = 0;
  for (y=-1; y < 2; y++)
    for (x=-1; x < 2; x=x+2)
      temp = temp + x*i[y][x];
      
  *o = temp;
}

NeighbourhoodToPixelOp()
sobely(in stream unsigned char i[-1..1][-1..1],
       out stream int *o)
{
  int x, y, temp;
  
  temp = 0;
  for (x=-1; x < 2; x++)
    for (y=-1; y < 2; y=y+2)
      temp = temp + y*i[y][x];
      
  *o = temp;
}

PixelToPixelOp()
magnitude(in stream int *i1,
  	  in stream int *i2,
	  out stream int *o)
{
  int temp;

  if (*i1 < 0) temp = -*i1;
  else         temp = *i1;
  if (*i2 < 0) temp = temp + -*i2;
  else         temp = temp + *i2;

  *o = temp;
}

PixelToPixelOp()
direction(in stream int *x,
  	  in stream int *y,
	  out stream unsigned char *d)
{
  int td = 0;
  int tx = *x;
  int ty = *y;

  td = (ty >= 0 && ty <=  tx) ? 1:td;
  td = (tx >= 0 && ty >=  tx) ? 2:td;
  td = (ty <= 0 && ty >=  tx) ? 5:td;
  td = (tx <= 0 && ty <=  tx) ? 6:td;

  /* These require 3 intermediate linememories! */

  td = (tx <= 0 && ty >= -tx) ? 3:td;
  td = (ty >= 0 && ty <= -tx) ? 4:td;
  td = (tx >= 0 && ty <= -tx) ? 7:td;
  td = (ty <= 0 && ty >= -tx) ? 8:td;
  
  *d = td;
}

PixelToPixelOp()
mask(in stream unsigned char *i,
     in stream int *m,
     out stream unsigned char *o,
     in int *threshold=scint(128))
{
  *o = (*m > *threshold)? (*i):0;
}

PixelToPixelOp()
mul(in stream unsigned char *i,
    out stream unsigned char *o,
    in int *factor=scint(31))
{
  *o = *i * *factor;
}

PixelToPixelOp()
splituchar(in stream unsigned char *i, out stream unsigned char *o1, out stream unsigned char *o2)
{
  *o1 = *i;
  *o2 = *i;
}

NeighbourhoodToPixelOp()
splitucharline(in stream unsigned char i[0][0], out stream unsigned char *o1, out stream unsigned char *o2)
{
  *o1 = i[0][0];
  *o2 = i[0][0];
}

PixelToPixelOp()
splitint(in stream int *i, out stream int *o1, out stream int *o2)
{
  *o1 = *i;
  *o2 = *i;
}

PixelToPixelOp()
pixelmerged(in stream int *x, in stream int *y,
           out stream unsigned char *o)
{
  int tx=*x, ty=*y, td=0, mag;
  
  if (tx < 0) mag = -tx;
  else        mag =  tx;
  if (ty < 0) mag = mag - ty;
  else        mag = mag + ty;

  td = (ty >= 0 && ty <=  tx) ? 1:td;
  td = (tx >= 0 && ty >=  tx) ? 2:td;
  td = (ty <= 0 && ty >=  tx) ? 5:td;
  td = (tx <= 0 && ty <=  tx) ? 6:td;

  /* These require 3 intermediate linememories! */

  td = (tx <= 0 && ty >= -tx) ? 3:td;
  td = (ty >= 0 && ty <= -tx) ? 4:td;
  td = (tx >= 0 && ty <= -tx) ? 7:td;
  td = (ty <= 0 && ty >= -tx) ? 8:td;
  
  *o = (mag > 128)? (td):0;
}

NeighbourhoodToPixelOp()
edgedir(in stream unsigned char i[-1..1][-1..1], out stream unsigned char *o)
{
  int x, y, sx, sy, mag, dir;
  
  sx = 0;
  for (y=-1; y < 2; y++)
    for (x=-1; x < 2; x=x+2)
      sx = sx + x*i[y][x];
  sy = 0;
  for (x=-1; x < 2; x++)
    for (y=-1; y < 2; y=y+2)
      sy = sy + y*i[y][x];

  if (sx < 0) mag = -sx;
  else        mag =  sx;
  if (sy < 0) mag = mag - sy;
  else        mag = mag + sy;

  dir = 0;
  dir = (sy >= 0 && sy <=  sx) ? 1:dir;
  dir = (sx >= 0 && sy >=  sx) ? 2:dir;
  dir = (sy <= 0 && sy >=  sx) ? 5:dir;
  dir = (sx <= 0 && sy <=  sx) ? 6:dir;

  /* These require 3 intermediate linememories! */

  dir = (sx <= 0 && sy >= -sx) ? 3:dir;
  dir = (sy >= 0 && sy <= -sx) ? 4:dir;
  dir = (sx >= 0 && sy <= -sx) ? 7:dir;
  dir = (sy <= 0 && sy >= -sx) ? 8:dir;

  *o = (mag > 128)? (dir):0;
}

GlobalOp()
hough(in stream unsigned char **i, out stream unsigned char **o)
{
#define M_PI 3.14159265358979323846264338327950288419716
#define PHIS 128
#define RADIUS 25
  int y, x, p, c;
  float fp;
  char sintab[PHIS], costab[PHIS];

  double sin(double x);
  double cos(double x);
  fp = 0;
  for (p=0; p < PHIS; p++)
  {
    sintab[p] = sin(fp)*RADIUS;
    costab[p] = cos(fp)*RADIUS;
    
    fp = fp + (2.*M_PI)/PHIS;
  }
  memset(o, 0, _lines*_stride*sizeof(unsigned char));
  c=0;  
  for (y=RADIUS; y < _lines-RADIUS; y = y + 1)
    for (x=RADIUS; x < _stride-RADIUS; x = x + 1)
      if (i[y][x])
      {
        #pragma TCS_unroll=16
        for (p=(i[y][x]-1)*(PHIS/8); p < i[y][x]*(PHIS/8); p++)
          o[y+sintab[p]][x+costab[p]]=o[y+sintab[p]][x+costab[p]]+4;
        c++;
      }
  printf("%d on pixels\n", c);
}

ReductionOp()
imgMax(in stream unsigned char *i, in int *prevval, out int *outval, in int *prevc, out int*outc, in int* prevmaxc, out int* outmaxc)
{
  if (*i > *prevval)
  {
    *outval = *i;
    *outmaxc = *prevc;
  }
  *outc = *prevc + 1;
}

MAINTYPE MAIN(int argc, char **argv)
{
  int i=0, j, k, maxval, maxc, dummy;
  STREAMPTR a=1, b=2, c=3, d=4, e=5, f=6, g=7;
  char text[64];
  tmr_t timer = tmrInit();
  scInit(argc, argv);

/*  for (i=0; i < TRIALS; i++)
  {
    tmrStart(&timer);   
*/    generate(scint(1024), a);
    interpolate(a, a);
    splitucharline(a, b, c);
    sobelx(b, b);
    sobely(c, c);
    splitint(b, d, e);
    splitint(c, f, g);
    magnitude(d, f, b);
    direction(e, g, c);
    mask(c, b, a, scint(128));
    hough(a, a);
    imgMax(a, scint(0), &maxval, scint(0), &dummy, scint(0), &maxc);
/*
    _schedule(0);

    _awaitall();
    tmrStop(&timer);

    fprintf(OUTSTREAM, "%% max value %d at %d\n", maxval, maxc);
    fprintf(OUTSTREAM, "T(%d, %d) = %f;\n", 1, i+1, tmrGetValueInUs(&timer)/1000.0);
  }
  for (i=0; i < TRIALS; i++)
  {
    tmrStart(&timer);   
    generate(scint(1024), a);
    interpolate(a, a);
    edgedir(a, a);
    hough(a, a);
    discard(a);

    _schedule(0);

    _awaitall();
    tmrStop(&timer);

    fprintf(OUTSTREAM, "T(%d, %d) = %f;\n", 2, i+1, tmrGetValueInUs(&timer)/1000.0);
  }
*/
  return scExit();
}
